package cc.ilzy.mall.user.controller;

import cc.ilzy.mall.constants.CommonConstants;
import cc.ilzy.mall.exceptions.ExceptionEnum;
import cc.ilzy.mall.user.service.impl.INotifyService;
import cc.ilzy.mall.utils.ApiResponse;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

@Api(value = "通知相关接口", tags = "通知相关接口")
@RequestMapping("/api/notify/v1")
@Controller
@Slf4j
@Validated
public class NotifyController {
    @Resource
    private DefaultKaptcha kaptcha;
    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Resource
    private INotifyService notifyService;

    @ApiOperation("获取图形验证码")
    @GetMapping("/captcha")
    public void getCaptcha(HttpServletRequest request, HttpServletResponse response) {
        response.setDateHeader("Expires", 0L);
        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        response.addHeader("Cache-Control", "post-check=0, pre-check=0");
        response.setHeader("Pragma", "no-cache");
        response.setContentType("image/jpeg");
        String captchaCode = kaptcha.createText();
        log.info("生成的验证码: {}", captchaCode);
        // 将验证码存入Redis，设置过期时间为5分钟
        redisTemplate.opsForValue().set(getCaptchaKey(request), captchaCode, 5 , TimeUnit.MINUTES);
        try (ServletOutputStream outputStream = response.getOutputStream()) {
            ImageIO.write(kaptcha.createImage(captchaCode), "jpg", outputStream);
            outputStream.flush();
        } catch (IOException e) {
            log.error("获取图形验证码失败", e);
        }
    }

    /**
     * 发送注册验证码
     * @param to 接收验证码的手机号或邮箱
     * @param verifyCode 为了限流设置的验证码
     * @param request HttpServletRequest 对象
     */
    @ApiOperation(value = "发送注册验证码", notes = "发送注册验证码到指定手机号或邮箱")
    @ApiImplicitParams(value ={
            @ApiImplicitParam(name = "to", value = "接收验证码的手机号或邮箱", required = true, dataType = "String"),
            @ApiImplicitParam(name = "verifyCode", value = "为了限流设置的验证码", required = true, dataType = "String")
    })
    @ResponseBody
    @PostMapping("/sendVerityCode")
    public ApiResponse<Void> sendRegisterCode(@Email String to, @NotBlank String verifyCode, HttpServletRequest request) {
        // 这里可以调用短信服务发送验证码
        log.info("发送注册验证码到 {}: {}", to, verifyCode);
        // 实际发送逻辑
        String redisVerifyCode = redisTemplate.opsForValue().get(getCaptchaKey(request));
        if(StrUtil.isNotBlank(redisVerifyCode) && redisVerifyCode.equals(verifyCode)) {
            // 发送验证码逻辑
            notifyService.sendCode(CommonConstants.SendCodeEnum.REGISTER, to);
            log.info("验证码发送成功到: {}", to);
            return ApiResponse.success("验证码发送成功");
        } else {
            log.warn("图形验证码不匹配，发送失败");
            return ApiResponse.fail(ExceptionEnum.CODE_CAPTCHA);
        }
    }

    /**
     * 获取图形验证码的key key值得组成
     * 服务名: 功能名称: 随机8位
     * 例如：ilzy-mall-user:captcha:把ip和浏览器签名加密后取出8位
     *
     * @param request
     * @return
     */
    private String getCaptchaKey(HttpServletRequest request) {
        // String clientIP = CommonUtils.getIpAddr(request);
        String clientIP = ServletUtil.getClientIP(request, "");
        String userAgent = request.getHeader("User-Agent");

        // key 规范: 业务划分,冒号隔离
        // 防止ip漂移 需要加上IP地址和浏览器的指纹(user-agent)
        String key = "ilzy-mall-user:captcha:" + SecureUtil.md5(clientIP + userAgent);

        log.info("ip={}, userAgent={}, key={}", clientIP, userAgent, key);

        return key;
    }
}
































